package cn.edu.neu.lab603.cloudeval.strategy

import cn.edu.neu.lab603.cloudeval.entity._
import com.typesafe.scalalogging.LazyLogging

/** 实现一个简单的分配策略。
  * 该策略遍历所有实体机，如果发现合适的实体机，则尝试分配虚拟机。
  *
  * Created by yfwz100 on 16/9/24.
  */
class NaiveAllocationStrategy extends AllocationStrategy with LazyLogging {
  type VM = VirtualMachine
  type Host = PhysicalMachine

  override def allocateVMForCloudlet(cloudlet: CloudTask, dataCenter: DataCenter): VM = {
    val hosts = dataCenter.pmList.sortWith((a, b) => a.getVMList.size < b.getVMList.size)
    for (pm <- hosts) {
      if (pm.getStatus == PhysicalMachine.Status.ON) {
        try {
          val vm = pm.allocateVirtualMachine(cloudlet.getResSpecMap)
          vm.setCloudlet(cloudlet)
          cloudlet.setExecutionContext(vm)
          return vm
        } catch {
          case _: NoEnoughResForVM => logger.trace(s"No enough resource in Host#${pm.id}")
        }
      } else {
        pm.boot()
        throw new NoHostToAllocateException
      }
    }
    throw new NoHostToAllocateException
  }

  override def initDataCenterLayout(dataCenter: DataCenter): Unit = {
    // 打开所有物理机器
    dataCenter.pmList.foreach(_.boot())
  }

  override def deallocateVMForCloudlet(cloudlet: CloudTask, dataCenter: DataCenter): Unit = {
    val vm = cloudlet.getExecutionContext
    if (vm != null) {
      val pm = vm.host
      pm.deallocateVirtualMachine(cloudlet)

      if (pm.getStatus == PhysicalMachine.Status.ON && pm.getVMList.forall(_.isIdle)) {
        pm.shutdown()
      }
    } else {
      throw new RuntimeException("No VM found.")
    }
  }
}
